/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.formserver.vmmanager.service;

import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.GspCommonElement;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelActionType;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.lcm.metadata.spi.IMetadataReferenceManager;
import io.iec.edp.caf.commons.exception.CAFRuntimeException;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MetadataReferenceService implements IMetadataReferenceManager {

  private HashMap<String, String> map = new HashMap<String, String>();
  private String errorCode = "MetadataReferenceService";
  //TODO 临时添加
  private String errorToken = "#GSPBefError# ";
  private void buildMetadataReference(GspMetadata metadata)
  {
    if (metadata.getRefs() == null)
    {
      metadata.setRefs(new ArrayList<MetadataReference>());
    }
    map.clear();

    MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
    GspViewModel vm = (GspViewModel) metadata.getContent();
    addAssoVirtualFieldBeReference(vm,metadata,metadataService);
    // 虚拟vo无依赖
    if (vm.getIsVirtual())
    {
      return;
    }

    // ① vm.Mapping
    String beId = vm.getMapping().getTargetMetadataId();
    addMappingBeReference(beId, metadata, metadataService);

    // ② obj
    dealObjectReference(vm.getMainObject(), metadata, metadataService);

    // ③ vm.Actions
    if (vm.getActions() != null && vm.getActions().getCount() > 0)
    {
      for (ViewModelAction action : vm.getActions())
      {
        if (action.getType() == ViewModelActionType.VMAction)
        {
          if (action instanceof MappedCdpAction)
          {
            buildCompReference((MappedCdpAction) action, metadata, metadataService);
          }
						else
          {
            throw new CAFRuntimeException("", errorCode,errorToken+action.getName()+"类型应为MappedCdpAction. "+errorToken , null, ExceptionLevel.Error,false);
          }
        }
      }
    }

    // ④ vm.DataExtendInfo
    //todo:
  }
  private void addAssoVirtualFieldBeReference(GspViewModel viewModel, GspMetadata metadata, MetadataService metadataService) {
    List<IGspCommonElement> elementList = viewModel.getAllElementList(false);
    for(IGspCommonElement element : elementList)
    {
      if (!element.getIsVirtual() || element.getChildAssociations().size() == 0)
      {
        continue;
      }
      String virualRefBeId = ((GspCommonElement)element).getChildAssociations().get(0).getRefModelID();
      addMappingBeReference(virualRefBeId, metadata, metadataService);
    }
  }


  private void dealObjectReference(GspViewObject obj, GspMetadata metadata, MetadataService metadataService)
  {
    if (obj.getIsVirtual())
    {
      return;
    }

    // ① mapping
    addMappingBeReference(obj.getMapping().getTargetMetadataId(), metadata, metadataService);

    // ① Elemnet
    if (obj.getContainElements() != null && obj.getContainElements().getCount() > 0)
    {
      for (IGspCommonField ele : obj.getContainElements())
      {
        dealElementReference( (GspViewModelElement)ele, metadata, metadataService);
      }
    }

    // ② Child
    if (obj.getContainChildObjects() != null && obj.getContainChildObjects().getCount() > 0)
    {
      for (IGspCommonObject childObj : obj.getContainChildObjects())
      {
        dealObjectReference( (GspViewObject)childObj, metadata, metadataService);
      }
    }
  }

  private void dealElementReference(GspViewModelElement ele, GspMetadata metadata, MetadataService metadataService)
  {
    //① mapping
    if (!ele.getIsVirtualViewElement())
    {
      addMappingBeReference(ele.getMapping().getTargetMetadataId(), metadata, metadataService);
    }

    //② vmElement.Help
    //todo:
  }

  public void buildCompReference(MappedCdpAction operation, GspMetadata metadata, MetadataService metadataService)
  {
    addMappingBeReference(operation.getComponentEntityId(), metadata, metadataService);
  }

  private void addMappingBeReference(String refBeId, GspMetadata metadata, MetadataService metadataService)
  {
    if (refBeId==null ||"".equals(refBeId) || map.containsKey(refBeId))
    {
      return;
    }

    map.put(refBeId, refBeId);
    buildReference(refBeId, metadata, metadataService);
  }

  private void buildReference(String refMetadataId, GspMetadata metadata, MetadataService metadataService)
  {
    if (refMetadataId==null || "".equals(refMetadataId))
    {
      return;
    }
    for (MetadataReference metadataReference : metadata.getRefs()) {
      if (refMetadataId.equals(metadataReference.getDependentMetadata().getId())) {
        return;
      }
    }
    RefCommonService refService =SpringBeanUtils.getBean(RefCommonService.class);
    GspMetadata refMetaData=refService.getRefMetadata(refMetadataId);
    if(refMetaData==null){
      throw  new RuntimeException(String.format("VO元数据在构造依赖的元数据关系时，未找到ID值为：%1$s的元数据,请确认依赖的元数据是否部署到环境中!",refMetadataId));
    }
    MetadataReference metadataReference = new MetadataReference();
    metadataReference.setMetadata(metadata.getHeader());
    metadataReference.setDependentMetadata(refMetaData.getHeader());
    metadata.getRefs().add(metadataReference);
  }

  public List<MetadataReference> getConstraint(GspMetadata metadata)
  {
    if(metadata.getRefs()!=null){
      metadata.getRefs().clear();
    }
    buildMetadataReference(metadata);
    List<MetadataReference> list = new ArrayList<>();
    if (metadata.getRefs() != null && metadata.getRefs().size() > 0)
    {
      for (MetadataReference item : metadata.getRefs())
      {
        list.add(item);
      }
    }
    return list;
  }
}
